#!/usr/bin/env python
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2008, Matt Layman"
__author__ = "Matt Layman <laymansterms.dev@gmail.com>"

import unittest
import sys
import os
from pysqlite2 import dbapi2 as sqlite

sys.path += [os.path.abspath('..')]

from frontend.backend_connection import BackendConnection
from frontend.medialibrary.music import MusicLibrary
from frontend.medialibrary.music import MusicLibraryException
from frontend.medialibrary.music import Album, Track

class MockBackendConnection(BackendConnection):
    def __init__(self): pass
    def close_connection(self): pass

class TestMusicLibrary(unittest.TestCase):

    def setUp(self):
        self.debug = False
        # Create test music database
        self.TEST_DB = os.path.abspath('.' + '/data/' + self.__str__() + '.db')
        if os.path.exists(self.TEST_DB):
            os.remove(self.TEST_DB) # Start fresh to avoid table creation error
        self.connection = sqlite.connect(self.TEST_DB)
        self.cursor = self.connection.cursor()
        self.cursor.execute("""CREATE TABLE track(
                            filename TEXT,
                            title VARCHAR(255),
                            artist VARCHAR(255),
                            album VARCHAR(255),
                            tracknumber INTEGER,
                            bitrate INTEGER,
                            year INTEGER,
                            rating INTEGER DEFAULT NULL,
                            length INTEGER,
                            genre VARCHAR(128),
                            comment TEXT,
                            lyrics TEXT DEFAULT "",
                            PRIMARY KEY(filename))""")
        # Populate the test database with enough information to make it useful
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    sum = i + j + k # to get unique track numbers for ablums
                    db_row = ('filename%s' % str(i) + str(j) + str(k),
                              'title%s' % str(i) + str(j),
                              'artist%d' % i,
                              'album%d' % j,
                              'genre%d' % i,
                              i, # length
                              sum, # tracknumber
                              i, # bitrate
                              'comment%d' % i,
                              i  # year
                              )
                    self.cursor.execute("""INSERT INTO track(filename,
                                                             title,
                                                             artist,
                                                             album,
                                                             genre,
                                                             length,
                                                             tracknumber,
                                                             bitrate,
                                                             comment,
                                                             year) 
                                        VALUES(?,?,?,?,?,?,?,?,?,?)""", db_row)

        self.cursor.execute("""CREATE TABLE playlist(
                            title TEXT,
                            PRIMARY KEY(title))""")

        self.cursor.execute("""CREATE TABLE playlist_relation(
                            title TEXT,
                            filename TEXT,
                            PRIMARY KEY(title, filename))""")
        self.connection.commit()
        self.connection.close()        
        try:
            self.backend_connection = MockBackendConnection()
        except:
            print "\nbackend_connection failed"
        self.musiclibrary = MusicLibrary(self.backend_connection)
        self.musiclibrary.MUSIC_DB = self.TEST_DB

    def tearDown(self):
        self.backend_connection.close_connection()
        if not self.debug:
            if os.path.exists(self.TEST_DB):
                os.remove(self.TEST_DB)

    def testMusicLibraryConstructor(self):
        """testMusicLibraryContructor - Ensures instantiation of MusicLibrary 
        class"""
        self.assertTrue(isinstance(self.musiclibrary, MusicLibrary))

    def testGetPlaylist(self):
        #TODO: write this test, set up the playlist test table
        pass

    def testGetNumberOfTracksOnPlaylist(self):
        #TODO: write this test, set up the playlist test table
        pass

    def testGetTracksOnPlaylist(self):
        #TODO: write this test, set up the playlist test table
        pass

    def testGetAllArtists(self):
        """testGetAllArtists - Ensures that all artists are returned from
        the music library"""
        result = self.musiclibrary.get_all_artists()
        self.assertEqual(result, ['artist0', 'artist1'])

    def testGetAllTracks(self):
        """testGetAllTracks - Ensures that all tracks are returned"""
        result = self.musiclibrary.get_all_tracks()
        for i in result:
            self.assertTrue(isinstance(i, Track))
        self.assertEqual(len(result), 8)

    def testGetTracksByGenre(self):
        """testGetTracksByGenre - Ensures tracks of a certain genre are 
        returned"""
        result = self.musiclibrary.get_tracks_by_genre('genre0')
        self.assertEqual(len(result), 4)
        for i in result:
            self.assertEqual(i.get_genre(), 'genre0')

    def testGetTracksByMissingGenre(self):
        """testGetTracksByMissingGenre - Ensures proper handling of a missing
        genre"""
        self.assertEquals(len(self.musiclibrary.get_tracks_by_genre('foo-bar-baz**')), 0)

    def testGetTracksByArtist(self):
        """testGetTracksByArtist - Ensure tracks by a certain artist are
        returned"""
        result = self.musiclibrary.get_tracks_by_artist('artist1')
        self.assertEqual(len(result), 4)
        for i in result:
            self.assertEqual(i.get_artist(), 'artist1')

    def testGetTracksByUnknownArtist(self):
        """testGetTracksByUnknownArtist - Ensure proper handling of an missing
        artist in the cache"""
        self.assertEquals(len(self.musiclibrary.get_tracks_by_artist('foo')), 0)

    def testGetAllAlbums(self):
        """testGetAllAlbums - Ensures all albums are returned"""
        result = self.musiclibrary.get_all_albums()
        for i in result:
            self.assertTrue(isinstance(i, Album))
        self.assertEqual(len(result), 4)
        # TODO: This fails because albums with the same name are seen as
        # equal even though they are by different artists. This a bug and
        # a logic problem in the current music library code
    
    def testGetAlbumsByArtist(self):
        """testGetAlbumsByArtist - Ensures correct albums by an artist is
        returned"""
        result = self.musiclibrary.get_albums_by_artist('artist0')
        self.assertEqual(len(result), 4)
        for i in result:
            self.assertEqual(i.get_artist(), 'artist0')

    def testGetAlbumsByUnknownArtist(self):
        """testGetAlbumsByUnknownArtist - Ensures proper handling of an
        artist not in the cache"""
        self.assertEquals(len(self.musiclibrary.get_albums_by_artist('foo')), 0)

    def testNumberOfTracks(self):
        """testNumberOfTracks - Ensures number of all tracks is returned"""
        result = self.musiclibrary.number_of_tracks()
        self.assertEqual(result, 8)

    def testNumberOfTracksByArtist(self):
        """testNumberOfTracksByArtist - Ensures number of all tracks by one
        artist is returned"""
        result = self.musiclibrary.number_of_tracks_by_artist('artist0')
        self.assertEqual(result, 4)

    def testNumberOfTracksByUnknownArtist(self):
        """testNumberOfTracksByUnknownArtist - Ensures proper handling when
        artist called is not in the cache"""
        self.assertEqual(self.musiclibrary.number_of_albums_by_artist('foo'), 0)

    def testNumberOfAlbumsByArtist(self):
        """testNumberOfAlbumsByArtist - Ensures number of all albums by one
        artist is returned"""
        result = self.musiclibrary.number_of_albums_by_artist('artist1')
        self.assertEqual(result, 2)

    def testNumberOfAlbumsByUnknownArtist(self):
        """testNumberOfAlbumsByUnknownArtist - Ensures proper handling when
        artist called is not in the cache"""
        self.assertEqual(self.musiclibrary.number_of_albums_by_artist('foo'), 0)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestMusicLibrary)
    result = unittest.TextTestRunner(descriptions=2, verbosity=2).run(suite)
